﻿<script setup lang="ts" name="CropperWrap">
import type Cropper from 'cropperjs'
import { propTypes } from '@/utils/propTypes'
import { urlToBase64, getFileName } from '@/utils/file/helper'

const { t } = useI18n() // 国际化
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('cropper-wrap')

type CropendResult = {
  imgBase64: string;
  imgInfo: Cropper.Data;
}

const props = defineProps({
  srcValue: propTypes.string.def(''),
  circled: propTypes.bool.def(true)
})

const emit = defineEmits(['fileChange'])

let filename = ''
const src = ref('')
const previewSource = ref('')
const cropper = ref<Cropper>()
let scaleX = 1
let scaleY = 1

watch(
  ()=> props.srcValue,
  async (v) => {
    filename = getFileName(v)
    src.value = await urlToBase64(v)
  },
  { immediate: true }
)

const handleBeforeUpload = (file: File) => {
  const reader = new FileReader()
  reader.readAsDataURL(file)
  src.value = ''
  previewSource.value = ''
  reader.onload = function (e) {
    src.value = (e.target?.result as string) ?? ''
    filename = file.name
  }
  return false
}
const handleCropend = ({ imgBase64, imgInfo }: CropendResult) => {
  previewSource.value = imgBase64
  emit('fileChange', {
    filename: filename,
    value: previewSource.value,
    imgInfo: imgInfo
  })
}

const handleReady = (cropperInstance: Cropper) => {
  cropper.value = cropperInstance
  emit('fileChange', {
    filename: filename,
    value: previewSource.value
  })
}

const handlerToolbar = (event: string, arg?: number) => {
  if (event === 'scaleX') {
    scaleX = arg = scaleX === -1 ? 1 : -1
  }
  if (event === 'scaleY') {
    scaleY = arg = scaleY === -1 ? 1 : -1
  }
  cropper?.value?.[event]?.(arg)
}
</script>

<template>
  <div :class="prefixCls">
    <div :class="`${prefixCls}-left`">
      <div :class="`${prefixCls}-content`">
        <CropperImage v-if="src" :src="src" height="330px" :circled="circled" @cropend="handleCropend" @ready="handleReady" />
      </div>
      <div :class="`${prefixCls}-toolbar`">
        <div :class="`${prefixCls}-upload`">
          <ElUpload :fileList="[]" :show-file-list="false" accept="image/*" :beforeUpload="handleBeforeUpload">
            <ElTooltip :content="t('cropper', 'selectImage')" placement="bottom">
              <ElButton size="small" type="primary">
                <SvgIcon icon="ad:upload-outlined" />
              </ElButton>
            </ElTooltip>
          </ElUpload>
        </div>
        <div :class="`${prefixCls}-operate`">
          <ElTooltip :content="t('action', 'reset')" placement="bottom">
            <ElButton size="small" type="primary" :disabled="!src" @click="handlerToolbar('reset')">
              <SvgIcon icon="ad:reload-outlined" />
            </ElButton>
          </ElTooltip>
          <ElTooltip :content="t('cropper', 'rotateLeft')" placement="bottom">
            <ElButton size="small" type="primary" :disabled="!src" @click="handlerToolbar('rotate', -45)">
              <SvgIcon icon="ad:rotate-left-outlined" />
            </ElButton>
          </ElTooltip>
          <ElTooltip :content="t('cropper', 'rotateRight')" placement="bottom">
            <ElButton size="small" type="primary" :disabled="!src" @click="handlerToolbar('rotate', 45)">
              <SvgIcon icon="ad:rotate-right-outlined" />
            </ElButton>
          </ElTooltip>
          <ElTooltip :content="t('cropper', 'horizontalFlip')" placement="bottom">
            <ElButton size="small" type="primary" :disabled="!src" @click="handlerToolbar('scaleX')">
              <SvgIcon icon="ci:horizontal-flip" />
            </ElButton>
          </ElTooltip>
          <ElTooltip :content="t('cropper', 'verticalFlip')" placement="bottom">
            <ElButton size="small" type="primary" :disabled="!src" @click="handlerToolbar('scaleY')">
              <SvgIcon icon="ci:vertical-flip" />
            </ElButton>
          </ElTooltip>
          <ElTooltip :content="t('cropper', 'zoomIn')" placement="bottom">
            <ElButton size="small" type="primary" :disabled="!src" @click="handlerToolbar('zoom', 0.1)">
              <SvgIcon icon="ad:zoom-in-outlined" />
            </ElButton>
          </ElTooltip>
          <ElTooltip :content="t('cropper', 'zoomOut')" placement="bottom">
            <ElButton size="small" type="primary" :disabled="!src" @click="handlerToolbar('zoom', -0.1)">
              <SvgIcon icon="ad:zoom-out-outlined" />
            </ElButton>
          </ElTooltip>
        </div>
      </div>
    </div>
    <div :class="[prefixCls + '-right', circled ? 'is-circle' : '']">
      <div :class="`${prefixCls}-preview`">
        <img v-if="previewSource" :src="previewSource" />
      </div>
      <div v-if="previewSource" :class="`${prefixCls}-group`">
        <el-avatar :src="previewSource" :size="32" :shape="props.circled ? 'circle' : 'square'" />
        <el-avatar :src="previewSource" :size="48" :shape="props.circled ? 'circle' : 'square'" />
        <el-avatar :src="previewSource" :size="64" :shape="props.circled ? 'circle' : 'square'" />
        <el-avatar :src="previewSource" :size="96" :shape="props.circled ? 'circle' : 'square'" />
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
$prefix-cls: #{$namespace}-cropper-wrap;

.#{$prefix-cls} {
  display: flex;
  flex-direction: row;

  &-left,
  &-right {
    height: 360px;
  }

  &-left {
    width: 55%;
  }

  &-right {
    width: 45%;
    padding-left: var(--el-space);

    &.is-circle {
      .#{$prefix-cls}-preview {
        border-radius: 50%;
      }
    }
  }

  &-content {
    height: 330px;
    background: #eee;
    background-image: linear-gradient(45deg,
        rgb(0, 0, 0, 0.25) 25%,
        transparent 0,
        transparent 75%,
        rgb(0, 0, 0, 0.25) 0),
      linear-gradient(45deg,
        rgb(0, 0, 0, 0.25) 25%,
        transparent 0,
        transparent 75%,
        rgb(0, 0, 0, 0.25) 0);
    background-position: 0 0, 12px 12px;
    background-size: 24px 24px;
  }

  &-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 6px;

    :deep(.el-upload) {
      vertical-align: top;
    }

    .el-button+.el-button {
      margin-left: 6px;
    }

    .el-button--small {
      padding: 5px 7px;
    }
  }

  &-preview {
    width: 224px;
    height: 224px;
    margin: 0 auto;
    overflow: hidden;
    border: 1px solid var(--el-border-color-lighter);

    img {
      width: 100%;
      height: 100%;
    }
  }

  &-group {
    display: flex;
    padding-top: 20px;
    margin-top: 20px;
    border-top: 1px solid var(--el-border-color-lighter);
    align-items: center;
    justify-content: space-around;
  }
}
</style>
